<?php
/**
 * Celebrio Core
 * 
 * @copyright  Copyright (c) 2011 Celebrio Software
 * @package    Celebrio
 * @subpackage Core
 */
namespace Celebrio\Core;

use Nette\Object;

use Celebrio\Core\Manifest;
use Celebrio\Core\ServiceProvider;

/**
 * Handles the module installation (the activation in the system) which
 * always includes creating config file, sometimes also database records,
 * initial file/folder creating or configuring and so on.
 *
 * @author pavel
 */
class ModuleInstaller extends Object {
    
    public function install(Manifest $manifest, $configuration = array()) {
        
        $this->checkDependencies($manifest);
        
        if ($manifest->isAbstract()) {
            throw new \Exception("Trying to install abstract module directly");
        }
        
        // register globaly accessible service
        ServiceProvider::registerService($manifest);
        
        // initialize via module init class and get installed version
        $installedVersion = $this->initClassInstall($manifest, $configuration);
        
        // set abstract installed in installed.ini
        if ($manifest->isImpl()) {
            $manifestLoader = new ManifestLoader();
            $abstract = $manifestLoader->getAbstract($manifest);
            
            Config::current()->install($abstract->getFullNameDots(), ManifestType::ABSTR);
        }
        
        // set implementation/service/app installed in installed.ini
        Config::current()->install($manifest->getFullNameDots(), $installedVersion);
    }

    public function uninstall(Manifest $manifest, $abstract = false) {

        // TODO: check dependencies

        if ($manifest->isAbstract() && !$abstract) {
            throw new \Exception("Trying to uninstall abstract module directly.");
        }

        $initClass = $manifest->getInit();
        
        //set module name to init class property
        $moduleName = $manifest->getFullNameDots();
        $initClass->setModuleName($moduleName);
        
        if ($initClass !== null) {
            $initClass->uninstall();
        } else {
            if ($abstract) {
                // there is no init in abstract module, let's skip this
            } else {
                throw new \Exception("Null init class when trying to uninstall module.");
            }
        }

        
        
        
        
        Config::current()->uninstall($manifest->getFullNameDots());
        
        
        // abstract module (if there's any and no other implementation of it is installed) should be uninstalled as well
    	if ($manifest->isImpl()) {
        	$manifestLoader = new ManifestLoader();
        	$abstract = $manifestLoader->getAbstract($manifest);
        	$interface = $abstract->getInterfaceFullNameDots();

        	$service = ServiceProvider::getAllServices($interface);	

        	if(count($service)==1) {
        		Config::current()->uninstall($abstract->getFullNameDots());
        	}

        }
        
    }
    
    private function initClassInstall(Manifest $manifest, $configuration) {
        $initClass = $manifest->getInit();
        if ($initClass !== null) {
            $newConfig = $initClass->changeConfig($configuration);
            $initClass->install($newConfig);
            Config::current()->saveConfigArray($newConfig, $manifest->getFullNameDots());
            
            //get version
            return $initClass->getInstalledVersion();
        }
    }
    
    public function upgrade(Manifest $manifest, $configuration = array()) {
        if ($manifest->isAbstract()) {
            throw new \Exception("Can't upgrade abstract module.");
        }
        
        $initClass = $manifest->getInit();
        
        //set module name to init class property
        $moduleName = $manifest->getFullNameDots();
        $initClass->setModuleName($moduleName);
        
        if ($initClass !== null) {
            $configuration = Config::current()->loadConfigArray($manifest->getFullNameDots());
            $newConfig = $initClass->upgradeConfig($configuration);
            $initClass->upgrade();
            Config::current()->saveConfigArray($newConfig, $manifest->getFullNameDots());
        } else {
            throw new \Exception("Null init class when trying to upgrade module.");
        }

        // initialize via module init class and get installed version
        $installedVersion = $initClass->getInstalledVersion();
        
        // set implementation/service/app installed in installed.ini
        Config::current()->upgrade($manifest->getFullNameDots(), $installedVersion);
    }
    
    private function findAbstract(Manifest $manifest) {
        
    }
    
    private function checkDependencies(Manifest $manifest) {
        //\Nette\Debug::dump("Dependencies are OK for now (testing version).");
    }

}

